home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue65 / alfresco / ValidateNumber.dpr < prev   
Encoding:
Text File  |  2000-11-28  |  9.3 KB  |  330 lines

  1. {*********************************************************}
  2. {* ValidateNumber                                        *}
  3. {* Copyright (c) Julian M Bucknall 2001                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco: Validate a number with an NFA    *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. program ValidateNumber;
  14.  
  15. {$APPTYPE CONSOLE}
  16.  
  17. uses
  18.   SysUtils;
  19.  
  20. function NFAValidateNumber(const S : string) : boolean;
  21. const
  22.   Digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
  23. type
  24.   TState = (StartScanning,               {state A in figure}
  25.             ScannedSign,                 {state B in figure}
  26.             ScanInteger,                 {state C in figure}
  27.             ScanLeadDigits,              {state D in figure}
  28.             ScannedDecPoint,             {state E in figure}
  29.             ScanLeadDecPoint,            {state F in figure}
  30.             ScanDecimalDigits);          {state G in figure}
  31.   TChoice = packed record
  32.     chInx   : integer;
  33.     chMove  : integer;
  34.     chState : TState;
  35.   end;
  36. var
  37.   i     : integer;
  38.   State : TState;
  39.   Ch    : char;
  40.   Move  : integer;
  41.   ChoiceStack : array [0..9] of TChoice;
  42.   ChoiceSP    : integer;
  43. begin
  44.   {assume the number is invalid}
  45.   Result := false;
  46.   {initialize the choice stack}
  47.   ChoiceSP := 0;
  48.   {prepare for scanning}
  49.   Move := 0;
  50.   i := 1;
  51.   State := StartScanning;
  52.   while i <= length(S) do begin
  53.     Ch := S[i];
  54.     case State of
  55.       StartScanning :
  56.         begin
  57.           case Move of
  58.             0 :
  59.               begin
  60.                 if (Ch = '+') then begin
  61.                   with ChoiceStack[ChoiceSP] do begin
  62.                     chInx := i;
  63.                     chMove := Move;
  64.                     chState := State;
  65.                   end;
  66.                   inc(ChoiceSP);
  67.                   State := ScannedSign;
  68.                   Move := 0;
  69.                   inc(i);
  70.                 end
  71.                 else
  72.                   inc(Move);
  73.               end;
  74.             1 :
  75.               begin
  76.                 if (Ch = '-') then begin
  77.                   with ChoiceStack[ChoiceSP] do begin
  78.                     chInx := i;
  79.                     chMove := Move;
  80.                     chState := State;
  81.                   end;
  82.                   inc(ChoiceSP);
  83.                   State := ScannedSign;
  84.                   Move := 0;
  85.                   inc(i);
  86.                 end
  87.                 else
  88.                   inc(Move);
  89.               end;
  90.             2 :
  91.               begin
  92.                 with ChoiceStack[ChoiceSP] do begin
  93.                   chInx := i;
  94.                   chMove := Move;
  95.                   chState := State;
  96.                 end;
  97.                 inc(ChoiceSP);
  98.                 State := ScannedSign;
  99.                 Move := 0;
  100.               end;
  101.           else
  102.             if (ChoiceSP = 0) then
  103.               Exit; // error
  104.             dec(ChoiceSP);
  105.             with ChoiceStack[ChoiceSP] do begin
  106.               i := chInx;
  107.               Move := succ(chMove);
  108.               State := chState;
  109.             end;
  110.           end;{Move case}
  111.         end;
  112.       ScannedSign :
  113.         begin
  114.           case Move of
  115.             0 :
  116.               begin
  117.                 if (Ch in Digits) then begin
  118.                   with ChoiceStack[ChoiceSP] do begin
  119.                     chInx := i;
  120.                     chMove := Move;
  121.                     chState := State;
  122.                   end;
  123.                   inc(ChoiceSP);
  124.                   State := ScanInteger;
  125.                   Move := 0;
  126.                   inc(i);
  127.                 end
  128.                 else
  129.                   inc(Move);
  130.               end;
  131.             1 :
  132.               begin
  133.                 if (Ch in Digits) then begin
  134.                   with ChoiceStack[ChoiceSP] do begin
  135.                     chInx := i;
  136.                     chMove := Move;
  137.                     chState := State;
  138.                   end;
  139.                   inc(ChoiceSP);
  140.                   State := ScanLeadDigits;
  141.                   Move := 0;
  142.                   inc(i);
  143.                 end
  144.                 else
  145.                   inc(Move);
  146.               end;
  147.             2 :
  148.               begin
  149.                 if (Ch = DecimalSeparator) then begin
  150.                   with ChoiceStack[ChoiceSP] do begin
  151.                     chInx := i;
  152.                     chMove := Move;
  153.                     chState := State;
  154.                   end;
  155.                   inc(ChoiceSP);
  156.                   State := ScanLeadDecPoint;
  157.                   Move := 0;
  158.                   inc(i);
  159.                 end
  160.                 else
  161.                   inc(Move);
  162.               end;
  163.           else
  164.             if (ChoiceSP = 0) then
  165.               Exit; // error
  166.             dec(ChoiceSP);
  167.             with ChoiceStack[ChoiceSP] do begin
  168.               i := chInx;
  169.               Move := succ(chMove);
  170.               State := chState;
  171.             end;
  172.           end;{Move case}
  173.         end;
  174.       ScanInteger :
  175.         begin
  176.           case Move of
  177.             0 :
  178.               begin
  179.                 if (Ch in Digits) then
  180.                   inc(i)
  181.                 else
  182.                   inc(Move);
  183.               end;
  184.           else
  185.             if (ChoiceSP = 0) then
  186.               Exit; // error
  187.             dec(ChoiceSP);
  188.             with ChoiceStack[ChoiceSP] do begin
  189.               i := chInx;
  190.               Move := succ(chMove);
  191.               State := chState;
  192.             end;
  193.           end;{Move case}
  194.         end;
  195.       ScanLeadDigits :
  196.         begin
  197.           case Move of
  198.             0 :
  199.               begin
  200.                 if (Ch in Digits) then
  201.                   inc(i)
  202.                 else
  203.                   inc(Move);
  204.               end;
  205.             1 :
  206.               begin
  207.                 if (Ch = DecimalSeparator) then begin
  208.                   with ChoiceStack[ChoiceSP] do begin
  209.                     chInx := i;
  210.                     chMove := Move;
  211.                     chState := State;
  212.                   end;
  213.                   inc(ChoiceSP);
  214.                   State := ScannedDecPoint;
  215.                   Move := 0;
  216.                   inc(i);
  217.                 end
  218.                 else
  219.                   inc(Move);
  220.               end;
  221.           else
  222.             if (ChoiceSP = 0) then
  223.               Exit; // error
  224.             dec(ChoiceSP);
  225.             with ChoiceStack[ChoiceSP] do begin
  226.               i := chInx;
  227.               Move := succ(chMove);
  228.               State := chState;
  229.             end;
  230.           end;{Move case}
  231.         end;
  232.       ScannedDecPoint :
  233.         begin
  234.           case Move of
  235.             0 :
  236.               begin
  237.                 if (Ch in Digits) then
  238.                   inc(i)
  239.                 else
  240.                   inc(Move);
  241.               end;
  242.           else
  243.             if (ChoiceSP = 0) then
  244.               Exit; // error
  245.             dec(ChoiceSP);
  246.             with ChoiceStack[ChoiceSP] do begin
  247.               i := chInx;
  248.               Move := succ(chMove);
  249.               State := chState;
  250.             end;
  251.           end;{Move case}
  252.         end;
  253.       ScanLeadDecPoint :
  254.         begin
  255.           case Move of
  256.             0 :
  257.               begin
  258.                 if (Ch in Digits) then begin
  259.                   with ChoiceStack[ChoiceSP] do begin
  260.                     chInx := i;
  261.                     chMove := Move;
  262.                     chState := State;
  263.                   end;
  264.                   inc(ChoiceSP);
  265.                   State := ScanDecimalDigits;
  266.                   Move := 0;
  267.                   inc(i);
  268.                 end
  269.                 else
  270.                   inc(Move);
  271.               end;
  272.           else
  273.             if (ChoiceSP = 0) then
  274.               Exit; // error
  275.             dec(ChoiceSP);
  276.             with ChoiceStack[ChoiceSP] do begin
  277.               i := chInx;
  278.               Move := succ(chMove);
  279.               State := chState;
  280.             end;
  281.           end;{Move case}
  282.         end;
  283.       ScanDecimalDigits :
  284.         begin
  285.           case Move of
  286.             0 :
  287.               begin
  288.                 if (Ch in Digits) then
  289.                   inc(i)
  290.                 else
  291.                   inc(Move);
  292.               end;
  293.           else
  294.             if (ChoiceSP = 0) then
  295.               Exit; // error
  296.             dec(ChoiceSP);
  297.             with ChoiceStack[ChoiceSP] do begin
  298.               i := chInx;
  299.               Move := succ(chMove);
  300.               State := chState;
  301.             end;
  302.           end;{Move case}
  303.         end;
  304.     end;{case}
  305.   end;
  306.   {if we reach this point, the number is valid if we're in a
  307.    terminating state}
  308.   if (State = ScanInteger) or
  309.      (State = ScannedDecPoint) or
  310.      (State = ScanDecimalDigits) then
  311.     Result := true;
  312. end;
  313.  
  314. var
  315.   S : string;
  316.  
  317. begin
  318.   S := '+1';
  319.   writeln(S, ':', NFAValidateNumber(S));
  320.   S := '-12';
  321.   writeln(S, ':', NFAValidateNumber(S));
  322.   S := '12.';
  323.   writeln(S, ':', NFAValidateNumber(S));
  324.   S := '+12.3';
  325.   writeln(S, ':', NFAValidateNumber(S));
  326.   S := '-.1234';
  327.   writeln(S, ':', NFAValidateNumber(S));
  328.   readln;
  329. end.
  330.